/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hopfield;

import java.io.IOException;
import java.util.ArrayList;

/**
 *
 * @author usuario
 */
public class HopField {

    private final int qtdPadroes = 4, qtdNeuronios = 45;
    Arquivo dados;
    private static double[][] m_identidade;

    public HopField(Arquivo dados) {

        this.dados = dados;

        m_identidade = new double[qtdNeuronios][qtdNeuronios];

        for (int i = 0; i < qtdNeuronios; i++) {
            for (int j = 0; j < qtdNeuronios; j++) {
                if (i == j) {
                    m_identidade[i][j] = 1;
                }
            }
        }
    }

    private int sinal(double u) {
        if (u >= 0) {
            return 1;
        } else {
            return -1;
        }
    }

    public void recuperaPadrao(int sinalRuidoso) throws IOException {

        int v_atual[], v_ant[] = new int[qtdNeuronios];
        ArrayList<int[]> ruidos, padroes = new ArrayList<int[]>();
        int u[] = new int[qtdNeuronios];
        double[] aux = new double[qtdNeuronios];

        ruidos = dados.leituraArquivo("ruidos");
        padroes = dados.leituraArquivo("padroes");

        double[][] W = new double[qtdNeuronios][qtdNeuronios];

        W = defineMatrizPeso(padroes);

        for (int i = 0; i < qtdNeuronios; i++) {
            v_ant[i] = 5;
        }

        v_atual = ruidos.get(sinalRuidoso).clone();

        while (!comparaVetor(v_ant, v_atual)) {

            for (int a = 0; a < qtdNeuronios; a++) {
                v_ant[a] = v_atual[a];
            }

            for (int j = 0; j < 45; j++) {
                for (int k = 0; k < 45; k++) {
                    aux[j] += W[j][k] * v_ant[k];
                }
            }

            for (int i = 0; i < u.length; i++) {
                u[i] = sinal(aux[i]);
            }

            for (int a = 0; a < qtdNeuronios; a++) {
                v_atual[a] = u[a];
            }
        }

        int cont = 0;

        System.out.println("--- Imagem Transmitida (padrão) ---");
        System.out.println("");

        int flag = 0;

        if (sinalRuidoso <= 2) {
            flag = 0;
        }
        if (sinalRuidoso <= 5 && sinalRuidoso > 2) {
            flag = 1;
        }
        if (sinalRuidoso <= 8 && sinalRuidoso > 5) {
            flag = 2;
        }
        if (sinalRuidoso <= 11 && sinalRuidoso > 8) {
            flag = 3;
        }


        for (int i = 0; i < qtdNeuronios; i++) {
            if (padroes.get(flag)[i] == 1) {
                System.out.print(" @ ");
                cont++;
            }
            if (padroes.get(flag)[i] != 1) {
                System.out.print(" - ");
                cont++;
            }
            if (cont == 5) {
                System.out.println(" ");
                cont = 0;
            }
        }

        System.out.println("");

        cont = 0;

        System.out.println("--- Imagem Ruidosa ---");
        System.out.println("");

        for (int i = 0; i < qtdNeuronios; i++) {
            if (ruidos.get(sinalRuidoso)[i] == 1) {
                System.out.print(" @ ");
                cont++;
            }
            if (ruidos.get(sinalRuidoso)[i] != 1) {
                System.out.print(" - ");
                cont++;
            }
            if (cont == 5) {
                System.out.println(" ");
                cont = 0;
            }
        }

        System.out.println("");

        cont = 0;

        System.out.println("--- Imagem Recuperada ---");
        System.out.println("");

        for (int i = 0; i < qtdNeuronios; i++) {
            if (v_atual[i] == 1) {
                System.out.print(" @ ");
                cont++;
            }
            if (v_atual[i] != 1) {
                System.out.print(" - ");
                cont++;
            }
            if (cont == 5) {
                System.out.println(" ");
                cont = 0;
            }
        }
        System.out.println("");
    }

    public double[][] defineMatrizPeso(ArrayList<int[]> x) {

        double[][] transposta = new double[qtdNeuronios][qtdNeuronios];
        double[][] W = new double[qtdNeuronios][qtdNeuronios];

        /* For faz o somatório*/
        for (int i = 0; i < qtdPadroes; i++) {

            //Multiplicação matriz coluna x matriz linha [z(k).z(k)¹]
            for (int a = 0; a < qtdNeuronios; a++) {
                for (int b = 0; b < qtdNeuronios; b++) {
                    transposta[a][b] += x.get(i)[a] * x.get(i)[b];
                }
            }
        }

        double identidade = 0;

        for (int i = 0; i < qtdNeuronios; i++) {
            for (int j = 0; j < qtdNeuronios; j++) {
                if (j == i) {
                    identidade = 1.0;
                } else {
                    identidade = 0.0;
                }
                W[i][j] = (transposta[i][j] * 1 / 45) - (4 / 45 * identidade);
            }
        }
        return W;
    }

    public boolean comparaVetor(int[] a, int b[]) {
        for (int i = 0; i < a.length; i++) {
            if (a[i] != b[i]) {
                return false;
            }
        }
        return true;
    }

    public double[][] escmatrix(double a, double[][] b) {

        int linhas = b.length;
        int colunas = b[0].length;

        double[][] c = new double[linhas][colunas];

        for (int i = 0; i < linhas; i++) {
            for (int j = 0; j < colunas; j++) {
                if (i == j) {
                    c[i][j] = a * b[i][j];
                }
            }
        }
        return c;
    }
}
